/**
 * Copyright 2007-2008. Chongqing First Information & Network Co., Ltd. All
 * rights reserved. <a>http://www.cqfirst.com.cn</a>
 */
package com.cqcis.uip.base.framework.base;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.cqcis.uip.base.framework.base.adaptor.AbstractRegisteredService;
import com.cqcis.uip.base.framework.common.Role;
import com.cqcis.uip.base.framework.common.Task;
import com.cqcis.uip.base.framework.core.RegisteredServiceContext;
import com.cqcis.uip.base.framework.handlers.common.AbstractDispatchHandler;
import com.cqcis.uip.base.framework.utils.LoopThreadPoolExecutor;


/**
 * 类表接口实现
 * 
 * @author huangmy
 * @date   2007-12-17
 */
public abstract class AbstractDispatcherSupport extends AbstractRegisteredService {	
	private static Log log = LogFactory.getLog(AbstractDispatcherSupport.class);
	
	private LoopThreadPoolExecutor executor;
	private AbstractDispatchHandler handler;
		
	private int threadNumberSchedule = 1;  /*如果线程分离, 处理任务线程的线程数*/
	private int threadNumberGet = 1;       /*如果线程分离, 获取任务线程的线程数*/	
	private int threadNumberResult = 1;    /*如果线程分离, 获取任务结果线程的线程数*/	
	
	@Override
	public boolean processResult(Task result) {
		if (result.isNormalPriority()) {
			return super.processResult(result);
		}
		
		return getSendTaskResultPriorityQueue().offer(result);
	}

	public void start(RegisteredServiceContext serviceContext) throws Exception {				
		super.start(serviceContext);
		
		int threadPoolCoreSize = 0;
		int threadPoolMaxSize = 0;
		
		threadPoolCoreSize = threadNumberSchedule + threadNumberGet + threadNumberResult;
		
		threadPoolMaxSize = threadPoolCoreSize * 2;
		
		executor = LoopThreadPoolExecutor.getExecutor(threadPoolCoreSize, 
				threadPoolMaxSize, 60, serviceContext.getLogService(), getLogConfiguration(), "(T)"+getInterfaceName(), getIntervalTime());
		
		handler.registerTaskQueue(getTaskQueue());
		handler.registerTaskResultQueue(getTaskResultQueue());
		handler.registerSendTaskQueue(getSendTaskQueue());
		handler.registerSendTaskResultQueue(getSendTaskResultQueue());			
		handler.registerInterfaceId(getInterfaceId());
		handler.registerTaskWaitTimeConsumePool(getTaskWaitTimeConsumePool());
		handler.registerAfterProcessResult(this);
		handler.registerSendTaskResultPriorityQueue(getSendTaskResultPriorityQueue());
		handler.registerSendTaskResultControlQueue(getSendTaskResultControlQueue());
		
		handler.start(serviceContext);
		
		for (int i = 0; i < threadNumberGet; i ++) {
			executor.execute(handler.getProcessTaskRunnable());
		}
		
		for (int i = 0; i < threadNumberResult; i ++) {
		    executor.execute(handler.getProcessTaskResultRunnable());
		}
		
		doStart();
	}
	
	public void stop(RegisteredServiceContext serviceContext) throws Exception {
		super.stop(serviceContext);
		
		handler.stop(serviceContext);
		
		if (executor != null) {
			executor.shutdown();
		}
		
		doStop();
	}
	
	public Role getRole() {		
		return Role.TABLE;
	}
		
	@Override
	protected boolean doSchedule() {		
		if ( (getTaskQueue().size() >= 0 
				&& (executor.getPoolSize() - threadNumberGet - threadNumberResult) < threadNumberSchedule
		      )
		   ) {
				executor.execute(handler.getScheduleRunnable());
				
			if (log.isDebugEnabled()) {
				log.debug("interfaceName: " + getInterfaceName() + ", new a thread to do schedule task.");
			}				
		}
				
		return true;
	}
	
	@Override
	protected boolean doScheduleSync(Task task) {
        boolean s = scheduleFor(task, false); // schedule
        if (!s) {
        	return false;
        }
		
		return waitForSyncTaskFinishBlockResult(task);
	}
		
	/**
	 * 定制启动
	 * @throws Exception
	 */
	public abstract void doStart() throws Exception;
	
	/**
	 * 定制停止
	 * @throws Exception
	 */
	public abstract void doStop() throws Exception;
	
	public void setHandler(AbstractDispatchHandler handler) {
		this.handler = handler;
	}

	public void setThreadNumberSchedule(int threadNumberSchedule) {
		this.threadNumberSchedule = threadNumberSchedule;
	}

	public void setThreadNumberGet(int threadNumberGet) {
		this.threadNumberGet = threadNumberGet;
	}

	public void setThreadNumberResult(int threadNumberResult) {
		this.threadNumberResult = threadNumberResult;
	}
}
